﻿extern alias RoutineBase1000;
extern alias RoutineBase1100;
extern alias RoutineBase1120;

using System;
using System.Linq;
using System.Timers;
using Citi.Scheduler.Domain;
using Citi.Helpers;
using System.Configuration;
using System.IO;
using System.Threading;
using System.Collections.Generic;

namespace Citi.Scheduler.WindowsServices
{
    [Serializable]
    public class CurrentAction : MarshalByRefObject, RoutineBase1000::Citi.RoutineBase.ICurrentAction, RoutineBase1100::Citi.RoutineBase.ICurrentAction
    {
        public RoutineExecutionStatus CurrentStatus { get; set; }

        public override object InitializeLifetimeService()
        {
            return null;
        }

        public CurrentAction(RoutineExecution routineExecution)
        {
            RoutineExecution = routineExecution;
        }

        private RoutineExecution RoutineExecution { get; set; }

        public string Description
        {
            set
            {
                RoutineExecutionHistory.InsertHistory(RoutineExecution.Id, RoutineExecutionHistory.GetLastStatus(RoutineExecution.Id), value);
            }
        }
    }

    [Serializable]
    public class CurrentAction1120 : MarshalByRefObject, RoutineBase1120::Citi.RoutineBase.ICurrentAction
    {
        public RoutineExecutionStatus CurrentStatus { get; set; }

        public override object InitializeLifetimeService()
        {
            return null;
        }

        public CurrentAction1120(RoutineExecution routineExecution)
        {
            RoutineExecution = routineExecution;
        }

        private RoutineExecution RoutineExecution { get; set; }

        #region Timer Timeout

        private System.Timers.Timer timer = new System.Timers.Timer { Interval = 120000 };
        private string timerMessage;

        private void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            Description = timerMessage;
        }

        public void StartLog(string message)
        {
            timer.Elapsed += TimerOnElapsed;
            timerMessage = message;
            timer.Start();
        }

        public void StopLog()
        {
            timer.Stop();
        }

        #endregion

        public string Description
        {
            set
            {
                RoutineExecutionHistory.InsertHistory(RoutineExecution.Id, RoutineExecutionHistory.GetLastStatus(RoutineExecution.Id), value);
            }
        }

        #region Timer Runner Application

        private System.Timers.Timer timerRunner = new System.Timers.Timer { Interval = 5000 };
        private string runnerFilePath;
        private static string NetworkUser { get { return ConfigurationManager.AppSettings["NetworkUser"]; } }
        private static string NetWorkPassword { get { return ConfigurationManager.AppSettings["NetWorkPassword"]; } }
        private static string Domain { get { return ConfigurationManager.AppSettings["Domain"]; } }

        private void TimerRunnerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            try
            {
                using (NetworkShareAccesser.Access(runnerFilePath, NetworkUser, NetWorkPassword))
                {

                    var fileSystemWatcher = new FileSystemWatcher();

                    if (!File.Exists(runnerFilePath)) return;

                    var logs = File.ReadAllLines(runnerFilePath);

                    if (!logs.Any()) return;

                    File.WriteAllText(runnerFilePath, string.Empty);

                    LogLines(logs);
                }
            }
            catch (SchedulerException e)
            {
                throw e;
            }
            catch (Exception)
            {
            }
        }

        private int countLinesLastRead;

        public void StartLogOnFile(string filePath)
        {
            try
            {
                runnerFilePath = filePath;

                //using (GetImpersonateUser())
                using (NetworkShareAccesser.Access(filePath, NetworkUser, NetWorkPassword))
                {
                    if (File.Exists(filePath)) File.Delete(filePath);

                    File.Create(filePath);

                    var fileSystemWatcher = new FileSystemWatcher(Path.GetDirectoryName(filePath), Path.GetFileName(filePath));
                    fileSystemWatcher.Changed += fileSystemWatcher_Changed;
                    fileSystemWatcher.EnableRaisingEvents = true;
                }
            }
            catch (Exception e)
            {
                Description = string.Format("Error on StartLogOnFile. {0}", e.Message);
            }

            //timerRunner.Elapsed += TimerRunnerOnElapsed;
            //runnerFilePath = filePath;
            //timerRunner.Start();
        }

        private ImpersonateUser GetImpersonateUser()
        {
            var impersonate = new ImpersonateUser();

            if (!string.IsNullOrWhiteSpace(Domain) && !string.IsNullOrWhiteSpace(NetworkUser) && !string.IsNullOrWhiteSpace(NetWorkPassword))
                impersonate.Impersonate(Domain, NetworkUser.Split(new[] { '\\' }).Last(), NetWorkPassword);

            return impersonate;
        }

        void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            Log(e.FullPath);
        }

        private void Log(string path)
        {
            try
            {
                //using (GetImpersonateUser())
                using (NetworkShareAccesser.Access(path, NetworkUser, NetWorkPassword))
                {
                    var lines = File.ReadLines(path).ToList();
                    var currentCount = lines.Count();

                    if (currentCount <= countLinesLastRead) return;

                    lines.RemoveRange(0, countLinesLastRead);
                    countLinesLastRead = currentCount;

                    LogLines(lines);
                }
            }
            catch (SchedulerException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                Description = string.Format("Error on Log Method. {0}", e.Message);
            }
        }

        private void LogLines(IEnumerable<string> lines)
        {
            foreach (var log in lines.Where(x => !string.IsNullOrWhiteSpace(x)))
            {
                //CurrentStatus = RoutineExecutionStatus.InProgress;
                Description = log;

                if (log.ToUpper().StartsWith("#ERROR"))
                    throw new SchedulerException(log);
            }
        }

        public void StopLogOnFile()
        {
            var stopDate = DateTime.Now;

            Log(runnerFilePath);
            //while (File.ReadLines(runnerFilePath).Any() && (DateTime.Now - stopDate).TotalSeconds < 60)
            //    Thread.Sleep(100);

            timerRunner.Stop();
        }

        #endregion
    }
}
